---
title: QueryBuilder
description: The root component and context provider
---

import { DemoLink } from '@site/src/components/DemoLink';

%importmd ../\_ts_admonition.md

The primary export of `react-querybuilder` is the `<QueryBuilder />` React component.

`QueryBuilder` uses the [`useQueryBuilder`](../utils/hooks#usequerybuilder) hook to merge props with context values and default values, generate update methods, and prepare the query schema.

## Subcomponents

`QueryBuilder` renders a [`RuleGroup`](./rulegroup) representing the root of the query.

The root `RuleGroup` is wrapped in a `<div>` with the [standard `queryBuilder` class](../styling/classnames), custom classes from [`controlClassnames.queryBuilder`](#controlclassnames), and `data-` attributes indicating enabled features like [drag-and-drop](#enabledraganddrop) and inline combinators.

Everything is wrapped in `<QueryBuilderStateProvider>` and `<QueryBuilderContext.Provider>`, which inherit ancestor context values and propagate them to subcomponents. Props take precedence over context values.

## Props

All `QueryBuilder` props are optional, but `fields` and `onQueryChange` are typically required for useful functionality (see [getting started guide](../intro)).

:::note

`RuleGroupTypeAny` refers to either `RuleGroupType` or `RuleGroupTypeIC` types. See [independent combinators](#independent-combinators) for `RuleGroupTypeIC` details.

:::

### `fields`

`OptionList<Field> | Record<string, Field>`

Array of [fields](../typescript#fields) or [option groups](../typescript#miscellaneous) containing field arrays. Alternatively, pass an object where keys are field `name`s and values are field definitions. Object format sorts field options alphabetically by `label` in the [`fieldSelector` component](./querybuilder-controlelements#fieldselector).

:::tip

Field objects can include custom properties. The complete field object is passed as `fieldData` to `OperatorSelector` and `ValueEditor` components (see [`controlElements`](#controlelements)).

:::

### `onQueryChange`

`(query: RuleGroupTypeAny) => void`

Called with the updated query whenever changes are made within the component.

### `query`

`RuleGroupTypeAny`

Query object of type `RuleGroupType` or `RuleGroupTypeIC`. When provided, makes `<QueryBuilder />` a [controlled component](https://reactjs.org/docs/forms.html#controlled-components).

Use with [`onQueryChange`](#onquerychange) for controlled component behavior. See [examples here](https://github.com/react-querybuilder/react-querybuilder/blob/main/examples).

### `defaultQuery`

`RuleGroupTypeAny`

The initial query when `<QueryBuilder />` is uncontrolled.

:::caution

Don't provide both `query` and `defaultQuery` props. Use `query` + `onQueryChange` for controlled components, or `defaultQuery` (or neither) for uncontrolled components. `onQueryChange` fires on every update regardless.

Providing both props logs errors in development mode. Switching between defined/undefined `query` across renders also logs errors.

:::

### `context`

`any`

Container for passing arbitrary props to custom components. Default components ignore this prop, but it's passed to all components throughout the `QueryBuilder` tree.

### `operators`

`OptionList<Operator>`

Array of available operators. Custom operators require `label` and either `name` or `value` (`value` takes precedence). Optional `arity` property ("unary", "binary", or number) determines value editor rendering—no value editor shows when `arity` is "unary" or < 2.

Use [`getOperators`](#getoperators) to build operator lists dynamically per field. Non-null `getOperators` results override this prop.

The default operator list is below.

%importcode /packages/core/src/defaults.ts#region=docs-operators

### `combinators`

`OptionList`

Array of combinators for RuleGroups. Default combinator list:

%importcode /packages/core/src/defaults.ts#region=docs-combinators

### `baseField`

`Record<string, unknown>`

Properties applied to all field objects. Individual field properties override base properties.

### `baseOperator`

`Record<string, unknown>`

Properties applied to all operator objects from `operators` prop or [`getOperators`](#getoperators). Individual operator properties override base properties.

### `baseCombinator`

`Record<string, unknown>`

Properties applied to all combinator objects. Individual combinator properties override base properties.

### `controlClassnames`

`Partial<Classnames>`

Assign custom CSS classes to QueryBuilder controls. Each property accepts `Classname` types: `string`, `string[]`, or `Record<string, any>` (see [`clsx` docs](https://www.npmjs.com/package/clsx)):

#### Usage example

Example: Adding "bold" class to "+ Rule" buttons (with CSS rule `.bold { font-weight: bold; }`):

```tsx
function App() {
  return (
    <QueryBuilder controlClassnames={{ addRule: 'bold' }}>
  )
}
```

| Property         | Class(es) applied to...                                                                    |
| ---------------- | ------------------------------------------------------------------------------------------ |
| `queryBuilder`   | the outermost <code>&lt;div&gt;</code> element                                             |
| `ruleGroup`      | each <code>&lt;div&gt;</code> wrapping a group                                             |
| `header`         | each <code>&lt;div&gt;</code> wrapping a group's header controls                           |
| `body`           | each <code>&lt;div&gt;</code> wrapping a group's body elements (child rules/groups)        |
| `combinators`    | each <code>&lt;select&gt;</code> control for combinators                                   |
| `addRule`        | each <code>&lt;button&gt;</code> that adds a rule                                          |
| `addGroup`       | each <code>&lt;button&gt;</code> that adds a group                                         |
| `cloneRule`      | each <code>&lt;button&gt;</code> that clones a rule                                        |
| `cloneGroup`     | each <code>&lt;button&gt;</code> that clones a group                                       |
| `removeGroup`    | each <code>&lt;button&gt;</code> that removes a group                                      |
| `lockRule`       | each <code>&lt;button&gt;</code> that locks/disables a rule                                |
| `lockGroup`      | each <code>&lt;button&gt;</code> that locks/disables a group                               |
| `notToggle`      | each <code>&lt;label&gt;</code> on a "not" (aka "inversion") toggle                        |
| `rule`           | each <code>&lt;div&gt;</code> containing a rule                                            |
| `fields`         | each <code>&lt;select&gt;</code> control for selecting a field                             |
| `matchMode`      | each <code>&lt;select&gt;</code> control for match modes                                   |
| `matchThreshold` | each <code>&lt;input&gt;</code> for match thresholds                                       |
| `operators`      | each <code>&lt;select&gt;</code> control for selecting an operator                         |
| `value`          | each <code>&lt;input&gt;</code> for entering a value                                       |
| `removeRule`     | each <code>&lt;button&gt;</code> that removes a rule                                       |
| `shiftActions`   | each <code>&lt;span&gt;</code> wrapping the up/down controls for shifting rules/groups     |
| `dragHandle`     | each <code>&lt;span&gt;</code> acting as a drag handle                                     |
| `valueSource`    | each <code>&lt;select&gt;</code> control for selecting a value source                      |
| `actionElement`  | each <code>&lt;button&gt;</code> control                                                   |
| `valueSelector`  | each <code>&lt;select&gt;</code> control                                                   |
| `betweenRules`   | inline combinator elements                                                                 |
| `valid`          | valid rules and groups                                                                     |
| `invalid`        | invalid rules and groups                                                                   |
| `dndDragging`    | rules and groups while being dragged                                                       |
| `dndOver`        | rules and groups hovered over by a dragged element                                         |
| `dndCopy`        | rules and groups hovered over by a dragged element when the drop effect is "copy"          |
| `dndGroup`       | rules and groups hovered over by a dragged element when the <kbd>Ctrl</kbd> key is pressed |
| `disabled`       | disabled elements                                                                          |
| `valueListItem`  | each element in a series of value editors                                                  |
| `branches`       | (not applied, but see [Styling overview](../styling/overview#branch-lines))                |
| `hasSubQuery`    | rules that render a subquery                                                               |
| `loading`        | [async value selectors](../tips/async-option-lists) during "loading" state                 |

### `controlElements`

`Partial<Controls>`

See [`controlElements`](./querybuilder-controlelements) for a list of all control elements and their props.

### `getOperators`

`(field: string, misc: { fieldData: Field }) => OptionList<Operator> | null`

Returns allowed operators for the given `field`. Returning `null` uses the [operators](#operators) prop (or defaults).

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getValueEditorType`

`(field: string, operator: string, misc: { fieldData: Field }) => ValueEditorType`

Returns the [`ValueEditor`](./valueeditor) type for the given `field` and `operator`. Options: `"text"` (default), `"select"`, `"multiselect"`, `"checkbox"`, `"radio"`, `"textarea"`, `"switch"`.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getValueSources`

`(field: string, operator: string, misc: { fieldData: Field }) => ValueSources | ValueSourceFullOptions`;

Returns allowed value sources for a given `field` and `operator`. Must return array with `"value"`, `"field"`, or both. Array elements can be `FlexibleOption` objects with `name`/`value` of `"value"` or `"field"`.

Defaults to `() => ["value"]`. First array element becomes the initial selection.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getValueEditorSeparator`

`(field: string, operator: string, misc: { fieldData: Field }) => ReactNode`;

Returns separator element between multiple value editors (e.g., for "between" operator). Can return any React element, including strings ("and", "to") or HTML elements.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getInputType`

`(field: string, operator: string, misc: { fieldData: Field }) => string`

Returns the `type` attribute for `<input />` elements. Only applies when [`getValueEditorType`](#getvalueeditortype) returns `"text"` or falsy. Defaults to `"text"`.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getValues`

`(field: string, operator: string, misc: { fieldData: Field }) => OptionList`

Returns allowed values for the given `field` and `operator`. Only applies when [`getValueEditorType`](#getvalueeditortype) returns `"select"`, `"multiselect"`, or `"radio"`. Defaults to empty array.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getMatchModes`

`(field: string, misc: { fieldData: Field }) => boolean | MatchMode[] | FlexibleOption<MatchMode>[]`

Returns valid `MatchMode`s for a field. Must return `MatchMode[]`, `Option<MatchMode>[]`, or `boolean`. `true` allows all match modes; other values disable match modes.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getSubQueryBuilderProps`

`(field: string, misc: { fieldData: Field }) => QueryBuilderProps`

Returns props for subqueries (see [Subqueries](../tips/subqueries)) to override parent query builder props. Props like `query`, `onQueryChange`, and `enableDragAndDrop` are ignored for subqueries.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getDefaultField`

`string | ((fieldsData: OptionList<Field>) => string)`

Default `field` for new rules. Accepts field `name` string or function returning field `name` based on `fields` prop.

### `getDefaultOperator`

`string | ((field: string, misc: { fieldData: Field }) => string)`

Default `operator` for new rules. Accepts operator `name` string or function returning operator `name`.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getDefaultValue`

`(rule: RuleType, misc: { fieldData: Field }) => any`

Returns default `value` for new rules based on existing rule properties.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getRuleClassname`

`(rule: RuleType, misc: { fieldData: Field }) => Classname`

Generates custom classes for rule outer `div` based on rule properties.

`fieldData` provides the complete `Field` object for accessing custom properties.

### `getRuleGroupClassname`

`(ruleGroup: RuleGroupTypeAny) => Classname`

Generates custom classes for group outer `div` based on group properties.

### `onAddRule`

`(rule: RuleType, parentPath: Path, query: RuleGroupTypeAny, context?: any) => RuleType | false`

Called before adding a new rule. Return modified `RuleType` object to proceed, or `false` to cancel. Use [`findPath`](../utils/misc#findpath) to locate the parent group. The `context` parameter passes data from custom [`addRuleAction`](./querybuilder-controlelements#addruleaction) components.

For [independent combinators](#independent-combinators), add `combinatorPreceding` property to specify the combinator before the new rule. Otherwise uses the last rule's combinator or first default combinator.

:::tip

To [prevent adding new rules](../tips/limit-groups), use `controlElements={{ addRuleAction: null }}` to hide the "+ Rule" button.

:::

### `onAddGroup`

`<RG extends RuleGroupTypeAny>(ruleGroup: RG, parentPath: Path, query: RG, context?: any) => RG | false`

Called before adding a new group. Return modified group object (same type: `RuleGroupType` or `RuleGroupTypeIC`) to proceed, or `false` to cancel. Use [`findPath`](../utils/misc#findpath) to locate the parent group. The `context` parameter passes data from custom [`addGroupAction`](./querybuilder-controlelements#addgroupaction) components.

For [independent combinators](#independent-combinators), add `combinatorPreceding` property to specify the combinator before the new group. Otherwise uses the last rule's combinator or first default combinator.

:::tip

To [prevent adding new groups](../tips/limit-groups), use `controlElements={{ addGroupAction: null }}` to hide the "+ Group" button.

:::

### `onMoveRule`

```
<RG extends RuleGroupTypeAny>(
  rule: RuleType,
  fromPath: Path,
  toPath: Path | 'up' | 'down',
  query: RG,
  nextQuery: RG,
  options: MoveOptions,
  context?: any
) => RG | boolean;
```

Called before a rule is moved or shifted. Return:

1. `true` - Allow the move/shift
2. `false` - Cancel the move/shift
3. New query object (based on `query` or `nextQuery` parameters)

### `onMoveGroup`

```
<RG extends RuleGroupTypeAny>(
  ruleGroup: RG,
  fromPath: Path,
  toPath: Path | 'up' | 'down',
  query: RG,
  nextQuery: RG,
  options: MoveOptions,
  context?: any
) => RG | boolean;
```

Called before a group is moved or shifted. Return:

1. `true` - Allow the move/shift
2. `false` - Cancel the move/shift
3. New query object (based on `query` or `nextQuery` parameters)

### `onRemove`

`<RG extends RuleGroupTypeAny>(ruleOrGroup: RG | RuleType, path: Path, query: RG, context?: any) => boolean`

Called before removing a rule or group. Return `true` to proceed or `false` to abort removal.

### `translations`

`Partial<Translations>`

Provides internationalization (i18n) support by overriding translatable texts for specific locales.

All object keys and properties are optional. The `translations` object deep-merges with defaults below. Default placeholder names are `"~"` and labels are `"------"`.

%importcode /packages/core/src/defaults.ts#region=docs-translations

### `showCombinatorsBetweenRules`

`boolean` (default `false`) _<DemoLink option="showCombinatorsBetweenRules" />_

Renders combinator selectors between child rules/groups instead of in the group header, encouraging more natural query reading.

The `combinator` property remains group-level—inline selectors update all combinators within the same group. For independently managed inline combinators, use [independent combinators](#independent-combinators).

### `showNotToggle`

`boolean` (default `false`) _<DemoLink option="showNotToggle" />_

Displays "Not" (inversion) toggle switch for each rule group.

### `showCloneButtons`

`boolean` (default `false`) _<DemoLink option="showCloneButtons" />_

Displays "clone" button on each group header and rule. Clicking creates an exact duplicate (with new `id`) positioned immediately after the original.

### `showLockButtons`

`boolean` (default `false`) _<DemoLink option="showLockButtons" />_

Displays "Lock rule" and "Lock group" buttons. Locked rules disable all elements except the lock button. Locked groups disable header elements (except lock button) and all child elements (including child lock buttons).

### `showMuteButtons`

`boolean` (default `false`) _<DemoLink option="showMuteButtons" />_

Displays "Mute rule" and "Mute group" buttons. By default, the `muted` property only affects `formatQuery`, which will ignore muted rules and groups (similar to "invalid" rules/groups).

### `showShiftActions`

`boolean` (default `false`) _<DemoLink option="showShiftActions" />_

Displays "shift up"/"shift down" buttons at the front of each rule and group (except root), stacked vertically by default. Upper button shifts up one position, lower button shifts down. Configure button labels via `translations.shiftActionUp` and `translations.shiftActionDown`.

### `resetOnFieldChange`

`boolean` (default `true`) _<DemoLink option="resetOnFieldChange" disabled />_

Pass `false` to preserve `operator` and `value` when `field` changes.

### `resetOnOperatorChange`

`boolean` (default `false`) _<DemoLink option="resetOnOperatorChange" />_

Resets `value` when `operator` changes.

### `enableMountQueryChange`

`boolean` (default `true`)

Pass `false` to disable `onQueryChange` on initial mount. Enabled by default because `query`/`defaultQuery` props are processed during first render and may differ from input (e.g., generated `id`s).

### `autoSelectField`

`boolean` (default `true`) _<DemoLink option="autoSelectField" disabled />_

Pass `false` to add an "empty" option (value `"~"`, label `"------"`) as first element in `fields` array. This becomes the initial selection for new rules. Empty field selection hides operator selector and value components. Customize via [`translations.fields.placeholder*`](#translations).

### `autoSelectOperator`

`boolean` (default `true`) _<DemoLink option="autoSelectOperator" disabled />_

Pass `false` to add an "empty" option (value `"~"`, label `"------"`) as first element in `operators` array. This becomes the initial selection for new rules. Empty operator selection hides value components. Customize via [`translations.operators.placeholder*`](#translations).

### `autoSelectValue`

`boolean` (default `true`) _<DemoLink option="autoSelectValue" disabled />_

Pass `false` to add an "empty" option (value `"~"`, label `"------"`) as first element in `values` array. This becomes the initial selection for rules with select list value editors. Customize via [`translations.values.placeholder*`](#translations).

### `addRuleToNewGroups`

`boolean` (default `false`) _<DemoLink option="addRuleToNewGroups" />_

Automatically adds a rule to new groups. When no `query`/`defaultQuery` prop is provided, adds a rule to the root group on mount. Groups with empty `rules` arrays don't receive automatic rules.

### `listsAsArrays`

`boolean` (default `false`) _<DemoLink option="listsAsArrays" />_

Updates rule values representing lists with proper arrays instead of comma-separated strings. Applies when `valueEditorType` is `"multiselect"` or `operator` is `"between"`, `"notBetween"`, `"in"`, or `"notIn"`.

For example, the default behavior for the "between" operator might produce this rule:

```json {4}
{
  "field": "f1",
  "operator": "between",
  "value": "f2,f3",
  "valueSource": "field"
}
```

When `listsAsArrays` is true, the rule's `value` will be an array:

```json {4}
{
  "field": "f1",
  "operator": "between",
  "value": ["f2", "f3"],
  "valueSource": "field"
}
```

### `parseNumbers`

`boolean | "enhanced" | "enhanced-limited" | "native" | "native-limited" | "strict" | "strict-limited"` (default `false`) _<DemoLink option="parseNumbers" />_

Sets `value` type as `number` instead of `string` when possible. See [Number parsing](../utils/misc#number-parsing) and [formatQuery option](../utils/export#parse-numbers).

:::info

Implemented in [`ValueEditor`](./valueeditor), not `QueryBuilder`. Custom value editors receive this prop but must implement the behavior themselves.

:::

### `enableDragAndDrop`

`boolean` (default `false`) _<DemoLink option="enableDragAndDrop" />_

:::caution

No need to set this prop directly—it only works when:

1. `QueryBuilderDnD` context provider from [`@react-querybuilder/dnd`](https://www.npmjs.com/package/@react-querybuilder/dnd) exists higher in the component tree
2. [`react-dnd`](https://www.npmjs.com/package/react-dnd) and [`react-dnd-html5-backend`](https://www.npmjs.com/package/react-dnd-html5-backend) are installed

When conditions are met and `enableDragAndDrop` isn't explicitly `false`, it becomes implicitly `true`.

:::

When `true`, displays a [drag handle](./draghandle) on the left side of each group header and rule for visual reordering.

#### Recommended usage

```bash
npm i react-querybuilder @react-querybuilder/dnd react-dnd react-dnd-html5-backend
# OR yarn add / pnpm add / bun add
```

```tsx
import { QueryBuilderDnD } from '@react-querybuilder/dnd';
import * as ReactDnD from 'react-dnd';
import * as ReactDndHtml5Backend from 'react-dnd-html5-backend';
import { QueryBuilder } from 'react-querybuilder';

const App = () => (
  <QueryBuilderDnD dnd={{ ...ReactDnD, ...ReactDndHtml5Backend }}>
    <QueryBuilder />
  </QueryBuilderDnD>
);
```

:::tip

If your app already uses [`react-dnd`](https://react-dnd.github.io/react-dnd/), use `QueryBuilderDndWithoutProvider` instead of `QueryBuilderDnD`. Both are functionally equivalent, but the former assumes an existing `<DndProvider />` higher in the tree. The latter renders its own `DndProvider`, causing conflicts with pre-existing ones (error: "Cannot have two HTML5 backends at the same time").

:::

### `disabled`

`boolean | Path[]` (default `false`) _<DemoLink option="disabled" />_

Pass `true` to disable all subcomponents and prevent query changes. Pass path array to disable specific rules/groups. Example: `disabled={[[0]]}` disables the top-most rule/group and its subcomponents only.

### `suppressStandardClassnames`

`boolean` (default `false`) _<DemoLink option="suppressStandardClassnames" />_

Disables standard classnames, including conditional and event-based classes for validation, drag-and-drop, etc.

### `debugMode`

`boolean` (default `false`) _<DemoLink option="debugMode" />_

Enables debug logging with the [`onLog` function](#onlog).

### `onLog`

`(message: any) => void` (default `console.log`)

Receives logging messages when [`debugMode`](#debugmode) is enabled.

### `idGenerator`

`() => string` (default `generateID`)

Generates `id`s for rules and groups without them, or clones needing new `id`s. Default generates valid v4 UUIDs per [RFC 4122](https://www.rfc-editor.org/rfc/rfc4122) using `crypto` package or `Math.random()` fallback.

### `accessibleDescriptionGenerator`

`(props: { path: Path; qbId: string; }) => string` (default `generateAccessibleDescription`)

Generates `title` attribute for each rule group's outermost `<div>`. For accessibility, output should be meaningful, descriptive, and unique within the page.

### `maxLevels`

`number` (default `Infinity`)

Limits query nesting levels. Adding groups beyond this limit gets ignored. Useful for preventing overly complex queries.

### `validator`

`QueryValidator` _<DemoLink option="validateQuery" />_

Executed on each render. Return boolean (`true` = valid, `false` = invalid) or object with rule/group `id`s as keys. Object values can be boolean or `{ valid: boolean, reasons?: array }`. The validation object gets passed to rule/group components. See [validation documentation](../utils/validation).

## Independent combinators

Props specifying `RuleGroupTypeAny` are inferred as [`RuleGroupType` or `RuleGroupTypeIC`](../typescript#rules-and-groups). `RuleGroupTypeIC` queries use "independent combinators."

This places combinator values between each neighboring rule/group pair (every odd-numbered index). Similar to [`showCombinatorsBetweenRules`](#showcombinatorsbetweenrules), but each combinator is independently controlled. Users often find this more natural as it mirrors natural language query expression.

A standard query (`RuleGroupType`) might look like this:

```ts
const query: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'f1', operator: '=', value: 'v1' },
    { field: 'f2', operator: '=', value: 'v2' },
  ],
};
```

The same query using independent combinators would look like this:

```ts
const query: RuleGroupTypeIC = {
  rules: [
    { field: 'f1', operator: '=', value: 'v1' },
    'and',
    { field: 'f2', operator: '=', value: 'v2' },
  ],
};
```

Click <DemoLink option="independentCombinators" text="here" /> to load the demo with a query using independent combinators.
